package libra;

import java.util.Properties;
import java.util.concurrent.Executor;

import org.junit.Before;
import org.junit.Test;

import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.ConfigType;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;

/**
 * 通过Java代码的方式实现与NacosConfig配置中心的编程式相互
 * 需要依赖项：
	<dependency>
		<groupId>com.alibaba.nacos</groupId>
		<artifactId>nacos-client</artifactId>		
	</dependency>
 */
public class NacosConfigByCoding {
	// 文件所属的组别
	String group = "DEFAULT_GROUP";
	
	ConfigService configService;
	
	/********************************
	 * NacosConfig配置中心相关API测试 *
	 ********************************/
	/**
	 * 初始化ConfigService，Nacos的所有API操作都与ConfigService相关
	 * @throws NacosException
	 */
	@Before
	public void init() throws NacosException {
		// 创建一个properties文件，并配置Nacos的服务地址
		Properties prop = new Properties();
		/*
		 * 如果是nacos单机，直接传入ip地址
		 * 如果是nacos集群，可配置多个IP地址，使用','号隔开
		 */
		//prop.put(PropertyKeyConst.SERVER_ADDR, "127.0.0.1:8848");
		prop.put(PropertyKeyConst.SERVER_ADDR, "127.0.0.1:8850,127.0.0.1:8860,127.0.0.1:8870");
		// 通过传入的properties配置文件，创建一个ConfigService配置中心服务
		ConfigService configService = NacosFactory.createConfigService(prop);
	}
	
	/**
	 * 通过Java代码的形式向NacosConfig发布配置文件
	 * 	如果配置文件不存在，则进行创建
	 * 	如果配置文件已存在，则会对其进行更新覆盖
	 * @throws Exception
	 */
	@Test
	public void publishConfig() throws NacosException {
		/*
		 * 向NacosConfig发布配置文件，数据以text文本格式进行保存
		 */
		// 文件标识ID
		String dataId = "publishBySDK.properties";
		// 向NacosConfig发布新的配置文件，以该种方式发布，服务端默认会以txt文本格式存储数据。因为ConfigType.getDefaultType()->text
		boolean isPublishOk = configService.publishConfig(dataId, group, "info=通过Sdk向NacosConfig配置中心发布新(修改!!!)的配置文件[publishBySDK.properties]");
		System.out.println( "发布"+dataId+"：" + isPublishOk );
		
		/*
		 * 向NacosConfig发布配置文件，数据以指定的ConfigType.YAML格式进行保存
		 */
		// 文件标识ID
		dataId = "publishBySDK.yml";
		// 向NacosConfig发布新的配置文件，以该种方式发布，服务端会以指定的数据格式存储数据。
		isPublishOk = configService.publishConfig(dataId, group, "info: 通过Sdk向NacosConfig配置中心发布新(修改!!!)的配置文件[publishBySDK.yml]",ConfigType.YAML.getType());
		System.out.println( "发布"+dataId+"：" + isPublishOk );
	}
	
	/**
	 * 通过Java代码的形式向NacosConfig删除配置文件
	 * 	如果配置文件不存在，则直接返回成功
	 * 	如果配置文件已存在，则进行删除再返回
	 * @throws Exception
	 */
	@Test
	public void removeConfig() throws NacosException {
		/*
		 * 向NacosConfig删除配置文件
		 */
		// 文件标识ID
		String dataId = "publishBySDK.properties";
		// 向NacosConfig删除配置文件。如果文件不存在，直接返回成功消息
		boolean isRemoveOk  = configService.removeConfig(dataId, group);
		System.out.println( "删除"+dataId+"：" + isRemoveOk );
		
		/*
		 * 向NacosConfig删除配置文件
		 */
		// 文件标识ID
		dataId = "publishBySDK.yaml";
		// 向NacosConfig删除配置文件。如果文件不存在，直接返回成功消息
		isRemoveOk  = configService.removeConfig(dataId, group);
		System.out.println( "删除"+dataId+"：" + isRemoveOk );
	}
	
	
	/**
	 * 通过Java代码的形式获取NacosConfig中指定dataId的配置文件
	 * 	如果配置文件不存在，返回null
	 * 	如果配置文件已存在，返回其实际的文本内容
	 * 读取配置超时或网络异常，抛出NacosException异常
	 * @throws Exception
	 */
	@Test
	public void getConfig() throws Exception {
		/*
		 * 获取NacosConfig中心的指定的properties配置文件 
		 */
		// 文件标识ID
		String dataId = "publishBySDK.properties";
		// 通过ConfigService.getConfig()获取指定配置文件，5000ms的超时时间
		String configContent = configService.getConfig(dataId, group, 5000);
		
		System.out.println( fmt(dataId, configContent) );
		
		/*
		 * 获取NacosConfig中心的指定的yml配置文件 
		 */
		// 文件标识ID
		dataId = "publishBySDK.yaml";
		// 通过ConfigService.getConfig()获取指定配置文件，5000ms的超时时间
		configContent = configService.getConfig(dataId, group, 5000);
		
		System.out.println( fmt(dataId, configContent) );
	}
	
	/**
	 * 为指定dataId配置文件
	 * 	'添加'Listern监听器，监听其的变更操作 
	 * 		如果被监听的配置文件不存在，不会报错
	 * 		如果被监听的配置文件已存在，且在被监听之前有发生过变更，则在添加Listener时会立即收到最近一次变更的回调(无论之前被修改了多少次)
	 * 	或
	 * 	'删除'Listern监听器，取消对配置文件的监听
	 * @throws Exception
	 */
	@Test
	public void add_Or_Remove_Listener() throws Exception {
		// 文件标识ID
		String dataId = "publishBySDK.yml";
		// 创建Listener监听器
		Listener listener = new Listener() {
			/*
			 * 接收NacosConfig的消息推送
			 * 每次服务端的dataId对应的配置文件发生变更时，都会回调该方法并将最新的内容通过该方法进行传入
			 * configInfo：监听的dataId对应的配置文件的文本内容
			 */
			@Override
			public void receiveConfigInfo(String configInfo) {
				System.out.println("监听变更的最新内容:" + configInfo);
			}
			@Override
			public Executor getExecutor() {
				return null;
			}
		};
		/*
		 * 添加Listener监听器
		 * 	如果被监听的配置文件不存在，不会报错
		 * 	如果被监听的配置文件已存在，且在被监听之前有发生过变更，则在添加Listener时会立即收到最近一次变更的回调(无论之前被修改了多少次)
		 */
		configService.addListener(dataId, group, listener);
		
		// 测试让主线程不退出，因为订阅配置是守护线程，主线程退出守护线程就会退出。 正式代码中无需下面代码
		while( true ) {
			int read = System.in.read();
			if( '0' == read ) 
				break;
			if( '1' == read) 
				/*
				 * 添加Listener监听器
				 * 	如果被监听的配置文件不存在，不会报错
				 * 	如果被监听的配置文件已存在，且在被监听之前有发生过变更，则在添加Listener时会立即收到最近一次变更的回调(无论之前被修改了多少次)
				 */
				configService.addListener(dataId, group, listener);
			if( '2' == read ) 
				/*
				 * 删除指定的监听器，取消监听后配置不会再推送
				 */
				configService.removeListener(dataId, group, listener);
		}
	}
	
	
	/** 格式化配置文件内容输出 **/
	private String fmt(String dataId, String content ){
		return String.format(
				">>>>>>>>>>>>>>> %s >>>>>>>>>>>>>>>>>\r\n" +
				"%s\r\n" +
				"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<", 
				dataId, content);
	}
}
